<?

class dbCon {

	static $_inst=null; // Instance Holder
	private static $_con=null; // This is the database connection
	private $_error=null; // PDOException

	function __construct(){
	}

	// Gets the instance.
	// This function should be called any time we need to access properties or
	// methods from the object.
	// Instead of using $this->, you would use self::getInstance()->
	// The only exception would be when called from in the constructor
	public function getInstance() {
		if (!isset(self::$_inst)) {
			$className = __CLASS__;
			self::$_inst = new $className;
		}
		return self::$_inst;
	}

	// Send this an assoc array with the following key/value pairs:
	// host = db host
	// db = database name to which to connect
	// un = username
	// pw = password
	public function connect($arrDetails=null) {
		$retVal = null;
		if (!is_null($arrDetails)) {
			$dbCon = self::getInstance();
			try {
				$dbCon->_con = new jjPDO($arrDetails);
				$retVal = true;
			}catch (PDOException $e) {
				$dbCon->_con = null;
				$dbCon->_error = $e;
			}
		}
		return $retVal;
	}


	// Returns a jjPDOStatement.
	public function runQuery($sql, $tokens=null) {
		$dbCon = self::getInstance();
		$retVal = null;
		$stmt = null;
		if ($sql && $dbCon->_checkConnection()) {
			$dbCon->_error = null;
			try {
				$stmt = $dbCon->getConnectionObj()->prepare($sql);
				$stmt->execute($tokens);
			} catch (PDOException $e) {
				if ($stmt) {
					$stmt->addExeception($e);
					$stmt->triggerFail();
				}
				$dbCon->_error = $e;
			}
			$retVal = $stmt;
		}
		return $retVal;
	}

	// Returns the value of the first field of the first row of the passed SQL.
	// It is suggested that you specify LIMIT 1 to prevent unneeded work by the Database.
	public function getSingleField($sql, $tokens=null) {
		$retVal = false;
		$dbCon = self::getInstance();
		$row = $dbCon->runQuery($sql, $tokens);
		if ($row) {
			if ($row->rowCount()>0) {
				$data = $row->fetch();
				foreach ($data as $k=>$v) {
					$retVal = $v;
					break;
				}
			}
		}
		return $retVal;
	}

	// Returns the first row of the passed SQL.
	// It is suggested that you specify LIMIT 1 to prevent unneeded work by the Database.
	public function fetchSingleRow($sql, $tokens=null) {
		$retVal = false;
		$dbCon = self::getInstance();
		$row = $dbCon->runQuery($sql, $tokens);
		if ($row) {
			if ($row->rowCount()>0) {
				$retVal = $row->fetch();
			}
		}

		return $retVal;
	}

	// Returns _error which is the last PDOException run through
	public function getError() {
		return self::getInstance()->_error;
	}

	// Returns the last InsertId for this object.
	public function lastInsertId() {
		return self::getInstance()->_con->lastInsertId();
	}

	public function getConnectionObj() {
		return self::getInstance()->_con;
	}

	// Returns true/false bases on self::$_con
	private function _checkConnection() {
		$dbConn = self::getInstance();
		return !is_null($dbConn->_con);
	}

	// If there is no value, return NULL
	public function valOrNull(&$input = null) {
		return ($input)?$input:null;
	}

} // dbCon

class jjPDO extends PDO {

	function __construct($d){
		parent::__construct("mysql:host=".$d['host'].";dbname=".$d['db'], $d['un'], $d['pw']);
		$this->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING);
		$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
		$this->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,true);
		$this->setAttribute(PDO::ATTR_STATEMENT_CLASS,array('jjPDOStatement',array($this)));
		$this->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
		$this->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC);
	}//end __construct()
}

class jjPDOStatement extends PDOStatement {

	private $failed = false;
	private $myException = null;

	private function __construct() {
	}

	protected function triggerFail() {
		$this->failed = true;
	}

	// Simply sets myException to the PDOException
	protected function addExeception(&$e) {
		$this->myException = $e;
	}


	// Returns failed status
	public function hasFailed() {
		return $this->failed;
	}

	// Returns the PDOException for this specific Statement
	public function getError() {
		return $this->myException;
	}
}
